#ifndef __BUOLA_GUI_X11_CX11TOOLKIT_H__
#define __BUOLA_GUI_X11_CX11TOOLKIT_H__

#include <buola/gui/x11/auto.h>
#include <buola/gui/ctoolkit.h>
#include <X11/Xlib.h>

namespace buola { namespace gui { namespace x11 {

class CX11Toolkit : public CToolkit
{
public:
    CX11Toolkit();
    ~CX11Toolkit();
    
    CX11Window *GetRootWindow();
    CX11Window *GetNewProxyWindow();

    //Keyboard helper functions
    void Start();
    void Finish();

    void StartDisplay();
    void FinishDisplay();

    void InitShapeExtension();
    void InitDamageExtension();

    static void InitKeys();

    //! from X to buola
    static EKeyMod GetMods(unsigned int);
    //! from X to buola
    static EKeyLock GetLocks(unsigned int);
    //! from X to buola
    static EMouseButton GetButtons(unsigned int);
    //! from buola to X
    static unsigned int GetXMods(EKeyMod=KEYMOD_NONE,EKeyLock=KEYLOCK_NONE);
    //! from X to buola
    static EKeyCode GetKey(KeySym);
    static KeySym GetKeySym(const TKey&);

    unsigned int GetKeyCode(const TKey &pKey);
    bool KeysEqual(const TKey &p1,const TKey &p2);

    virtual img::CSurface *GetNewPixmap(const CSize_i&,int pDepth=0,unsigned char *pData=nullptr,int pStride=0);

    long GetStockCursor(CPointer::EStock);
    long GetCursor(unsigned char*,unsigned char*,int,int,int);

    int GetDefaultDepth();

private:
    //Direct protocol access
    void GrabKey(const TKey&,EKeyMod,bool,CWindow* =nullptr);
    void UngrabKey(const TKey&,EKeyMod,CWindow* =nullptr);

    void UngrabPointer();

    Pixmap CreatePixmap(const CSize_i&,uint32_t,CWindow* =nullptr);
    void FreePixmap(Pixmap);

    //non-static direct access
    void Flush();
    void Synchronize();

    virtual void QueryPointer(CPhysicalWindow *pWindow,CPoint_d &pInWindow,CPoint_d &pInScreen);

    CPhysicalWindow *GetNewPhysicalWindow(CWindow *pWindow);

    CClipboard *GetClipboard(int pCB);

    virtual bool SupportsBuolaWMExtensions();

    img::CGC *GetOpenGLGC();

    //X helpers
public:
    Time GetTimeStamp()     {   return mLastTimeStamp;  }

    CX11Dispatcher *GetDispatcher() {   return mDispatcher; }

    Window GetRootID() { return DefaultRootWindow(mDisplay); }
    
    static void DisableSM();

//////////////////
// display info
//
public:
    CX11Display *mDisplay;
    CX11Window *mRootWindow;
    int mShapeEvent;
    int mShapeError;
    int mDamageEvent;
    int mDamageError;

//////////
// data
//
private:
    CX11Dispatcher *mDispatcher;

    Time mLastTimeStamp;

    static KeySym mKeyToKeysym[KEY_COUNT];
    static bool mKeysInit;
    static bool mSMDisabled;

    static CInitFunction mInitFunction;
    static CFinishFunction mFinishFunction;

    CX11Session *mSession;

    std::vector<Atom> mNETSupported;
    bool mNETSupportedInit;

    bool mBuolaWMExtensions;

    friend class CPixmap;
    friend class CX11GC;
    friend class CX11Window;
    friend class CX11Atoms;
    friend class CColor;
    friend class CAccelerator;
    friend class CX11Clipboard;
    friend class CX11Drag;
    friend class CX11Drop;
    friend class CX11Dispatcher;
    friend class CWindowWM;
};

/*namespace x11*/ } /*namespace gui*/ } /*namespace buola*/ }

#endif
